home *** CD-ROM | disk | FTP | other *** search
/ isnet Internet / Isnet Internet CD.iso / prog / hiz / 09 / 09.exe / adynware.exe / perl / lib / site / HTTP / Date.pm < prev    next >
Encoding:
Perl POD Document  |  1999-12-28  |  8.2 KB  |  299 lines

  1. package HTTP::Date;
  2.  
  3. =head1 NAME
  4.  
  5. time2str, str2time - date conversion routines
  6.  
  7. =head1 SYNOPSIS
  8.  
  9.  use HTTP::Date;
  10.  
  11.  $stringGMT = time2str(time);   # Format as GMT ASCII time
  12.  $time = str2time($stringGMT);  # convert ASCII date to machine time
  13.  
  14. =head1 DESCRIPTION
  15.  
  16. This module provides two functions that deal with the HTTP date format.
  17.  
  18. =head2 time2str([$time])
  19.  
  20. The time2str() function converts a machine time (seconds since epoch)
  21. to a string.  If the function is called without an argument, it will
  22. use the current time.
  23.  
  24. The string returned is in the format defined by the HTTP/1.0
  25. specification.  This is a fixed length subset of the format defined by
  26. RFC 1123, represented in Universal Time (GMT).  An example of this
  27. format is:
  28.  
  29.    Thu, 03 Feb 1994 17:09:00 GMT
  30.  
  31. =head2 str2time($str [, $zone])
  32.  
  33. The str2time() function converts a string to machine time.  It returns
  34. C<undef> if the format is unrecognized, or the year is not between 1970
  35. and 2038.  The function is able to parse the following formats:
  36.  
  37.  "Wed, 09 Feb 1994 22:23:32 GMT"       -- HTTP format
  38.  "Thu Feb  3 17:03:55 GMT 1994"        -- ctime(3) format
  39.  "Thu Feb  3 00:00:00 1994",           -- ANSI C asctime() format
  40.  "Tuesday, 08-Feb-94 14:15:29 GMT"     -- old rfc850 HTTP format
  41.  "Tuesday, 08-Feb-1994 14:15:29 GMT"   -- broken rfc850 HTTP format
  42.  
  43.  "03/Feb/1994:17:03:55 -0700"   -- common logfile format
  44.  "09 Feb 1994 22:23:32 GMT"     -- HTTP format (no weekday)
  45.  "08-Feb-94 14:15:29 GMT"       -- rfc850 format (no weekday)
  46.  "08-Feb-1994 14:15:29 GMT"     -- broken rfc850 format (no weekday)
  47.  
  48.  "1994-02-03 14:15:29 -0100"    -- ISO 8601 format
  49.  "1994-02-03 14:15:29"          -- zone is optional
  50.  "1994-02-03"                   -- only date
  51.  "1994-02-03T14:15:29"          -- Use T as separator
  52.  "19940203T141529Z"             -- ISO 8601 compact format
  53.  "19940203"                     -- only date
  54.  
  55.  "08-Feb-94"         -- old rfc850 HTTP format    (no weekday, no time)
  56.  "08-Feb-1994"       -- broken rfc850 HTTP format (no weekday, no time)
  57.  "09 Feb 1994"       -- proposed new HTTP format  (no weekday, no time)
  58.  "03/Feb/1994"       -- common logfile format     (no time, no offset)
  59.  
  60.  "Feb  3  1994"      -- Unix 'ls -l' format
  61.  "Feb  3 17:03"      -- Unix 'ls -l' format
  62.  
  63.  "11-15-96  03:52PM" -- Windows 'dir' format
  64.  
  65. The parser ignores leading and trailing whitespace.  It also allow the
  66. seconds to be missing and the month to be numerical in most formats.
  67.  
  68. The str2time() function takes an optional second argument that
  69. specifies the default time zone to use when converting the date.  This
  70. zone specification should be numerical (like "-0800" or "+0100") or
  71. "GMT".  This parameter is ignored if the zone is specified in the date
  72. string itself.  It this parameter is missing, and the date string
  73. format does not contain any zone specification then the local time
  74. zone is assumed.
  75.  
  76. If the year is missing, then we assume that the date is the first
  77. matching date I<before> current time.
  78.  
  79. =head1 BUGS
  80.  
  81. Non-numerical time zones (like MET, PST) are all treated like GMT.
  82. Do not use them.  HTTP does not use them.
  83.  
  84. The str2time() function has been told how to parse far too many
  85. formats.  This makes the module name misleading. To be sure it is
  86. really misleading you can also import the time2iso() and time2isoz()
  87. functions.  They work like time2str() but produce ISO-8601 formated
  88. strings (YYYY-MM-DD hh:mm:ss).
  89.  
  90. =head1 COPYRIGHT
  91.  
  92. Copyright 1995-1997, Gisle Aas
  93.  
  94. This library is free software; you can redistribute it and/or
  95. modify it under the same terms as Perl itself.
  96.  
  97. =cut
  98.  
  99.  
  100. $VERSION = sprintf("%d.%02d", q$Revision: 1.24 $ =~ /(\d+)\.(\d+)/);
  101. sub Version { $VERSION; }
  102.  
  103. require 5.002;
  104. require Exporter;
  105. @ISA = qw(Exporter);
  106. @EXPORT = qw(time2str str2time);
  107. @EXPORT_OK = qw(time2iso time2isoz);
  108.  
  109. use Time::Local ();
  110.  
  111. use strict;
  112. use vars qw(@DoW @MoY %MoY);
  113.  
  114. @DoW = qw(Sun Mon Tue Wed Thu Fri Sat);
  115. @MoY = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
  116. my $i = 0;
  117. foreach(@MoY) {
  118.    $MoY{lc $_} = $i++;
  119. }
  120.  
  121. my($current_month, $current_year) = (localtime)[4, 5];
  122.  
  123.  
  124.  
  125.  
  126. sub time2str (;$)
  127. {
  128.    my $time = shift;
  129.    $time = time unless defined $time;
  130.    my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($time);
  131.    sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT",
  132.        $DoW[$wday],
  133.        $mday, $MoY[$mon], $year+1900,
  134.        $hour, $min, $sec);
  135. }
  136.  
  137.  
  138.  
  139. sub str2time ($;$)
  140. {
  141.    local($_) = shift;
  142.    return undef unless defined;
  143.    my($default_zone) = @_;
  144.  
  145.    s/^\s*(?:sun|mon|tue|wed|thu|fri|sat)\w*,?\s*//i;
  146.  
  147.    my($day, $mon, $yr, $hr, $min, $sec, $tz, $aorp);
  148.    my $offset = 0;  # used when compensating for timezone
  149.  
  150.  PARSEDATE: {
  151.       ($day,$mon,$yr,$hr,$min,$sec,$tz) =
  152.     /^\s*
  153.      (\d\d?)               # day
  154.         (?:\s+|[-\/])
  155.      (\w+)                 # month
  156.         (?:\s+|[-\/])
  157.      (\d+)                 # year
  158.      (?:
  159.            (?:\s+|:)       # separator before clock
  160.         (\d\d?):(\d\d)     # hour:min
  161.         (?::(\d\d))?       # optional seconds
  162.      )?                    # optional clock
  163.         \s*
  164.      ([-+]?\d{2,4}|GMT|gmt)? # timezone
  165.         \s*$
  166.     /x
  167.       and last PARSEDATE;
  168.  
  169.       ($mon, $day, $hr, $min, $sec, $tz, $yr) =
  170.     /^\s*                  # allow intial whitespace
  171.      (\w{1,3})             # month
  172.         \s+
  173.      (\d\d?)               # day
  174.         \s+
  175.      (\d\d?):(\d\d)        # hour:min
  176.      (?::(\d\d))?          # optional seconds
  177.         \s+
  178.      (?:(GMT|gmt)\s+)?     # optional GMT timezone
  179.      (\d+)                 # year
  180.         \s*$               # allow trailing whitespace
  181.     /x
  182.       and last PARSEDATE;
  183.  
  184.       ($mon, $day, $yr, $hr, $min) =
  185.     /^\s*
  186.      (\w{3})               # month
  187.         \s+
  188.      (\d\d?)               # day
  189.         \s+
  190.      (?:
  191.         (\d\d\d\d) |       # year
  192.         (\d{1,2}):(\d{2})  # hour:min
  193.      )
  194.      \s*$
  195.        /x
  196.      and last PARSEDATE;
  197.  
  198.       ($yr, $mon, $day, $hr, $min, $sec, $tz) =
  199.     /^\s*
  200.       (\d{4})              # year
  201.          [-\/]?
  202.       (\d\d?)              # numerical month
  203.          [-\/]?
  204.       (\d\d?)              # day
  205.      (?:
  206.            (?:\s+|:|T|-)   # separator before clock
  207.         (\d\d?):?(\d\d)    # hour:min
  208.         (?::?(\d\d))?      # optional seconds
  209.      )?                    # optional clock
  210.         \s*
  211.      ([-+]?\d\d?:?(:?\d\d)?
  212.       |Z|z)?               # timezone  (Z is "zero meridian", i.e. GMT)
  213.         \s*$
  214.     /x
  215.       and last PARSEDATE;
  216.  
  217.       ($mon, $day, $yr, $hr, $min, $aorp) =
  218.         /^\s*
  219.           (\d{2})                # numerical month
  220.              -
  221.           (\d{2})                # day
  222.              -
  223.           (\d{2})                # year
  224.              \s+
  225.           (\d\d?):(\d\d)(am|pm)  # hour:min am or pm
  226.              \s*$
  227.         /ix
  228.           and last PARSEDATE;
  229.  
  230.       return undef;
  231.    }
  232.  
  233.    if ($mon =~ /^\d+$/) {
  234.      return undef if $mon < 1 || $mon > 12;
  235.      $mon--;
  236.    } else {
  237.      $mon = lc $mon;
  238.      return undef unless exists $MoY{$mon};
  239.      $mon = $MoY{$mon};
  240.    }
  241.  
  242.    unless (defined $yr) {
  243.     $yr = $current_year;
  244.     $yr-- if $mon > $current_month;
  245.     }
  246.  
  247.    return undef if $yr > 99 && $yr < 1900;  # We ignore these years
  248.    $yr += 100 if $yr < 50;  # a stupid thing to do???
  249.    $yr -= 1900 if $yr >= 1900;
  250.  
  251.  
  252.    return undef if $yr > 138;
  253.    return undef if $yr <  70;  # 1970 is Unix epoch
  254.  
  255.    if ($aorp) {
  256.        $aorp = uc $aorp;
  257.        $hr = 0 if $hr == 12 && $aorp eq 'AM';
  258.        $hr += 12 if $aorp eq 'PM';
  259.    }
  260.  
  261.    for ($sec, $min, $hr) {  $_ = 0 unless defined   }
  262.  
  263.    $tz = $default_zone unless defined $tz;
  264.    return Time::Local::timelocal($sec, $min, $hr, $day, $mon, $yr)
  265.      unless defined $tz;
  266.  
  267.    if ($tz =~ /^([-+])?(\d\d?):?(\d\d)?$/) {
  268.        $offset = 3600 * $2;
  269.        $offset += 60 * $3 if $3;
  270.        $offset *= -1 if $1 && $1 ne '-';
  271.    }
  272.    Time::Local::timegm($sec, $min, $hr, $day, $mon, $yr) + $offset;
  273. }
  274.  
  275.  
  276.  
  277.  
  278. sub time2iso (;$)
  279. {
  280.    my $time = shift;
  281.    $time = time unless defined $time;
  282.    my($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
  283.    sprintf("%04d-%02d-%02d %02d:%02d:%02d",
  284.        $year+1900, $mon+1, $mday, $hour, $min, $sec);
  285. }
  286.  
  287.  
  288. sub time2isoz (;$)
  289. {
  290.     my $time = shift;
  291.     $time = time unless defined $time;
  292.     my($sec,$min,$hour,$mday,$mon,$year) = gmtime($time);
  293.     sprintf("%04d-%02d-%02d %02d:%02d:%02dZ",
  294.             $year+1900, $mon+1, $mday, $hour, $min, $sec);
  295. }
  296.  
  297. 1;
  298.  
  299.